using System;
using System.Collections.Generic;
using System.Text;

namespace GuavaData
{
    public class UnpivotOp : Operator
    {
        // Performs an unpivot operation - translates normal rows into triples

        #region Fields
        Operator child;
        public Operator Child
        {
            get { return child; }
            set { child = value; }
        }

        List<string> foldColumns;
        public List<string> FoldColumns
        {
            get { return foldColumns; }
            set { foldColumns = value; }
        }

        string attCol;
        public string AttCol
        {
            get { return attCol; }
            set { attCol = value; }
        }

        string valCol;
        public string ValCol
        {
            get { return valCol; }
            set { valCol = value; }
        }

        string newAlias;
        public string NewAlias
        {
            get { return newAlias; }
            set { newAlias = value; }
        }
        #endregion Fields

        public UnpivotOp(Operator child, IEnumerable<string> foldColumns, string attCol, string valCol, string newAlias)
        {
            this.child = child;
            child.parent = this;
            this.foldColumns = new List<string>(foldColumns);
            this.attCol = attCol;
            this.valCol = valCol;
            this.newAlias = newAlias;

            // Create output schema - make sure that the domains of the various fold columns are equal
            Domain.Domain dWorking = null;
            this.exposedColumns = new List<string>();
            this.exposedDomains = new List<GuavaData.Domain.Domain>();
            for (int i = 0; i < child.exposedColumns.Count; i++)
            {
                if (this.foldColumns.Contains(child.exposedColumns[i]))
                {
                    if (dWorking == null)
                        dWorking = child.exposedDomains[i];
                    else if (dWorking != child.exposedDomains[i])
                        throw new Exception("Columns in the fold list of the unpivot operator do not have like domains.");
                }
                else
                {
                    this.exposedColumns.Add(child.exposedColumns[i]);
                    this.exposedDomains.Add(child.exposedDomains[i]);
                }
            }

            // If dWorking is still null, then we didn't find any pivot columns, and there is an error
            if (dWorking == null)
                throw new Exception("Did not find any pivot columns.");
            Domain.Enumerated e = new GuavaData.Domain.Enumerated(foldColumns);
            this.exposedColumns.Add(attCol);
            this.exposedColumns.Add(valCol);
            this.exposedDomains.Add(e);
            this.exposedDomains.Add(dWorking);
        }

        public override SqlText Visit(Provider qv)
        {
            return qv.Transform(this);
        }
        public override void Visit(Transform t, Command c)
        {
            t.Expand(this, c);
        }

        public override Operator Clone()
        {
            return new UnpivotOp(this.child.Clone(), this.foldColumns, this.attCol, this.valCol, this.newAlias);
        }

        public override void NotifyChange(Operator old, Operator newOp)
        {
            if (child == old)
            {
                this.child = newOp;
                newOp.parent = this;
            }
        }

        public override void Visit(Channel c, string table)
        {
            c.MapAliases(this, table);
        }

    }
}
